// main.cc 
//	Bootstrap code to initialize the operating system kernel.
//
//	Allows direct calls into internal operating system functions,
//	to simplify debugging and testing.  In practice, the
//	bootstrap code would just initialize data structures,
//	and start a user program to print the login prompt.
//
// 	Most of this file is not needed until later assignments.
//
// Usage: nachos -d <debugflags> -rs <random seed #>
//		-s -x <nachos file> -c <consoleIn> <consoleOut>
//		-f -cp <unix file> <nachos file>
//		-p <nachos file> -r <nachos file> -l -D -t
//              -n <network reliability> -m <machine id>
//              -o <other machine id>
//              -z
//
//    -d causes certain debugging messages to be printed (cf. utility.h)
//    -rs causes Yield to occur at random (but repeatable) spots
//    -z prints the copyright message
//
//  USER_PROGRAM
//    -s causes user programs to be executed in single-step mode
//    -x runs a user program
//    -c tests the console
//
//  FILESYS
//    -f causes the physical disk to be formatted
//    -cp copies a file from UNIX to Nachos
//    -p prints a Nachos file to stdout
//    -r removes a Nachos file from the file system
//    -l lists the contents of the Nachos directory
//    -D prints the contents of the entire file system 
//    -t tests the performance of the Nachos file system
//
//  NETWORK
//    -n sets the network reliability
//    -m sets this machine's host id (needed for the network)
//    -o runs a simple test of the Nachos network software
//
//  NOTE -- flags are ignored until the relevant assignment.
//  Some of the flags are interpreted here; some in system.cc.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#define MAIN
#include "copyright.h"
#undef MAIN

#include "utility.h"
#include "system.h"

// External functions used by this file

extern void ThreadTest(void), Copy(char *unixFile, char *nachosFile);
extern void Print(char *file), PerformanceTest(void);
extern void StartProcess(char *file), ConsoleTest(char *in, char *out);
extern void MailTest(int networkID);
#ifdef THREADS
extern void Problem2(void), TestSuite(void);
#endif

#ifdef NETWORK
extern void Server();
#endif

//----------------------------------------------------------------------
// main
// 	Bootstrap the operating system kernel.  
//	
//	Check command line arguments
//	Initialize data structures
//	(optionally) Call test procedure
//
//	"argc" is the number of command line arguments (including the name
//		of the command) -- ex: "nachos -d +" -> argc = 3 
//	"argv" is an array of strings, one for each command line argument
//		ex: "nachos -d +" -> argv = {"nachos", "-d", "+"}
//----------------------------------------------------------------------

int main(int argc, char **argv)
{
	int argCount;			// the number of arguments
	// for a particular command

	DEBUG('t', "Entering main");
	(void) Initialize(argc, argv);

	//#ifdef THREADS
	//  ThreadTest();
	//#endif

	for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount) {
		//cout << "Current argc: " << argc << "Current argv: " << argv << " = " << endl;
		//printf(*argv);
		argCount = 1;
		if (!strcmp(*argv, "-z"))               // print copyright
			printf (copyright);
#ifdef THREADS
		if (!strcmp(*argv, "-T"))               // Test Suite: link for this code is at the bottom of part 1 description
			TestSuite();
		if (!strcmp(*argv, "-P2"))               // Problem 2: for part 2
			Problem2();
#endif
#ifdef USER_PROGRAM
		if (!strcmp(*argv, "-x")) {        	// run a user program
			ASSERT(argc > 1);
			if(argc > 2){
				if(!strcmp (*(argv + 2), "-PFIFO")){
					cout << "Eviction policy is fifo" << endl;
					evictionPolicy = FIFO;
				}
				else if(!strcmp (*(argv + 2), "-PRAND")){
					cout << "Eviction policy is rand" << endl;
					evictionPolicy = RAND;
				}
			}

#ifdef NETWORK
			Delay(3);
#endif

			StartProcess(*(argv + 1));
			argCount = 2;
		}
		else if(!strcmp (*argv, "-PFIFO")){
			cout << "Eviction policy is fifo" << endl;
			evictionPolicy = FIFO;
		}

		else if (!strcmp(*argv, "-c")) {      // test the console
			if (argc == 1)
				ConsoleTest(NULL, NULL);
			else {
				ASSERT(argc > 2);
				ConsoleTest(*(argv + 1), *(argv + 2));
				argCount = 3;
			}
			interrupt->Halt();		// once we start the console, then
			// Nachos will loop forever waiting
			// for console input
		}
#endif // USER_PROGRAM

#ifdef FILESYS
		if (!strcmp(*argv, "-cp")) { 		// copy from UNIX to Nachos
			ASSERT(argc > 2);
			Copy(*(argv + 1), *(argv + 2));
			argCount = 3;
		} else if (!strcmp(*argv, "-p")) {	// print a Nachos file
			ASSERT(argc > 1);
			Print(*(argv + 1));
			argCount = 2;
		} else if (!strcmp(*argv, "-r")) {	// remove Nachos file
			ASSERT(argc > 1);
			fileSystem->Remove(*(argv + 1));
			argCount = 2;
		} else if (!strcmp(*argv, "-l")) {	// list Nachos directory
			fileSystem->List();
		} else if (!strcmp(*argv, "-D")) {	// print entire filesystem
			fileSystem->Print();
		} else if (!strcmp(*argv, "-t")) {	// performance test
			PerformanceTest();
		}
#endif // FILESYS
#ifdef NETWORK
		char *program;
		if (!strcmp(*argv, "-o")) {
			ASSERT(argc > 1);
			Delay(2); 				// delay for 2 seconds
			// to give the user time to
			// start up another nachos
			MailTest(atoi(*(argv + 1)));
			argCount = 2;
		}
		else if(!strcmp(*argv, "-tns")) {
			totalNumServers = atoi(*(argv + 1));
			if(DebugIsEnabled('n')) {
				cout << "totalNumServers set to: " << totalNumServers << endl;
			}
			argCount = 2;
		}
		else if(!strcmp(*argv, "-server")){
			Server();
		}
		else if(!strcmp(*argv, "-m")){
			myMachineID = atoi(*(argv + 1));
			argCount = 2;
			if(DebugIsEnabled('n')) {
				cout << "myMachineID set to: " << myMachineID << endl;
			}
		}
#endif // NETWORK
	}
	currentThread->Finish();	// NOTE: if the procedure "main"
	// returns, then the program "nachos"
	// will exit (as any other normal program
	// would).  But there may be other
	// threads on the ready list.  We switch
	// to those threads by saying that the
	// "main" thread is finished, preventing
	// it from returning.
	return(0);			// Not reached...
}
